﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using GuavaData;

using System.Data;

namespace ChannelConnector
{
    class Program
    {

        static private String server, catalog, port, user, password, channelPath, provider, gtreepath;
        static private int portNum;
        static private Boolean running;
        static private Thread listener;
        static private TcpListener tcpListener;

        static private List<Thread> clients;
        static private FileStream logFile;
        static private StreamWriter logWriter;
        static private Channel channel;


        static void Main(string[] args)
        {

            for (int i = 0; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "-p":
                        port = args[i + 1];
                        i++;
                        break;
                    case "-s":
                        server = args[i + 1];
                        i++;
                        break;
                    case "-u":
                        user = args[i + 1];
                        i++;
                        break;
                    case "-P":
                        password = args[i + 1];
                        i++;
                        break;
                    case "-d":
                        catalog = args[i + 1];
                        i++;
                        break;
                    case "-c":
                        channelPath = args[i + 1];
                        i++;
                        break;
                    case "-sp":
                        provider = args[++i];
                        break;
                    case "-g":
                        gtreepath = args[++i];
                        break;
                    default:
                        break;

                }
            }
            GTree gt = null;

             Schema initialSchema = null;



            if (gtreepath != null)
            {
                initialSchema = GuavaData.Schema.SchemaFromGTree(gtreepath);
            }
            //running = false;
            clients = new List<Thread>();
            channel = getChannelFromFile(channelPath);
            //channel = Channel.InvertChannel(channel);
            DBConnection.Provider = provider;
            SqlProvider.Provider = provider;

            Transaction prime = initialSchema.Transaction;
            channel.PoseTransactionWithEmptyProvider(prime);

            try
            {
                portNum = Int32.Parse(port);
            }
            catch
            {
                Console.WriteLine("invalid port");
                return;
            }
            //initialize mcserver
            try
            {
                McServer.Init("", server, catalog, user, password, channel);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
                Console.WriteLine("db connection failed");
                Console.WriteLine("User: " + user);
                Console.WriteLine("Password: " + password);
                Console.WriteLine("Port: " + port);
                Console.WriteLine("Server: " + server);
                Console.WriteLine("Catalog: " + catalog);
                Console.WriteLine("Provider: " + provider);
                System.Threading.Thread.Sleep(5000);
                return;
            }
            try
            {
                tcpListener = new TcpListener(IPAddress.Any, portNum);
            }
            catch
            {
                Console.WriteLine("invalid port");
                return;
            }
            listener = new Thread(new ThreadStart(GetClients));
            listener.Start();

            running = true;
        }

        private static void GetClients()
        {
            try
            {
                tcpListener.Start();
            }
            catch
            {
                Console.WriteLine("port in use");
                return;
            }

            try
            {
                while (true)
                {

                    TcpClient client = tcpListener.AcceptTcpClient();

                    Console.WriteLine("thread started");
                    Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                    clients.Add(clientThread);
                    clientThread.Start(client);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                Console.WriteLine("Socket Closed" + "\r\n");
            }
        }
        private static void HandleClientComm(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream networkStream = tcpClient.GetStream();
            String ip = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
            //this.SetText(ip + " connected" + "\r\n");
            System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
            System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
            try
            {
                string input = streamReader.ReadLine();

                StringWriter sw = null;
                if (input == null) { }
                else if (input.Equals("QUIT"))
                {
                    Console.WriteLine("quit recieved");
                    Environment.Exit(0);
                }
                else if (input.StartsWith("<?xml"))
                {
                    //this.SetText(ip + " requested query" + "\r\n");
                    String end = "";
                    while (!end.Equals("_END_"))
                    {
                        input += end;
                        end = streamReader.ReadLine();
                        //input += end;
                    }
                    //streamReader.Close();
                    String sql = McServer.queryString(XDocument.Parse(input));
                    //this.SetQueryText(sql);
                    Console.WriteLine(sql);
                    DataSet ds = McServer.tcpQueryDB(XDocument.Parse(input));
                    for (int i = 0; i < ds.Tables.Count; i++)
                    {
                        streamWriter.WriteLine(ds.Tables[i].Rows.Count.ToString());
                        string schema = "";
                        foreach (DataColumn dc in ds.Tables[i].Columns)
                        {
                            schema += "," + dc.ColumnName;
                        }
                        streamWriter.WriteLine(schema.Substring(1));
                        string row = "";
                        for (int j = 0; j < ds.Tables[i].Rows.Count; j++)
                        {
                            row = "";
                            foreach (object o in ds.Tables[i].Rows[j].ItemArray)
                            {
                                if (o is DBNull)
                                {
                                    row += ",NULL";
                                }
                                else row += "," + o.ToString();
                            }
                            streamWriter.WriteLine(row.Substring(1));
                            streamWriter.Flush();
                        }
                    }
                    streamWriter.Close();
                    //this.SetText(ip + " results sent" + "\r\n");
                }
                networkStream.Close();
                Environment.Exit(0);
            }
            catch (Exception ex)
            {
                //this.SetQueryText(ex.Message);
                streamWriter.WriteLine("DB error: " + ex.Message);
                streamWriter.Close();
                networkStream.Close();
                tcpClient.Close();
                Console.WriteLine("DB error: " + ex.Message);
                Console.WriteLine(ex.StackTrace);
                Environment.Exit(0);
                //this.SetText("Lost Client\r\n");
            }


            tcpClient.Close();
        }
        private static Channel getChannelFromFile(String path)
        {
            if (path == null) return null;

            XDocument doc = XDocument.Load(path);

            foreach (XElement xe in doc.Element("Channel").Elements())
            {
                if (xe.Name.LocalName == "initialSchema")
                {
                    xe.Remove();
                }

            }

            return Channel.FromXDocument(doc);
        }
        /*  private void btnStop_Click(object sender, EventArgs e)
          {
              if (running)
              {
                  this.tcpListener.Stop();
                  this.listener.Abort();
                  foreach (Thread t in clients)
                  {
                      t.Abort();
                  }
                  this.txtStatus.Text = "server stopped";
                  this.txtStatus.ForeColor = Color.Red;
                  this.txtLog.AppendText("Server stopped" + "\r\n");
                  logWriter.WriteLine(DateTime.Now.ToString() + " -- Server stopped");
                  logWriter.Flush();
                  running = false;
                  this.btnStart.Enabled = true;
              }
          }*/





    }
}

